<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>tick位移拆楼</title>

    <link rel="stylesheet" href="./lib/styles.css" />

    <script type="text/javascript" src="./lib/aircity/ac_conf.js"></script>
    <script type="text/javascript" src="./lib/aircity/ac.min.js"></script>
  </head>
  <body>
    <div id="player"></div>

    <div class="btn" onclick="begin()">开始拆楼</div>
    <div class="btn" onclick="reset()" style="right: 220px">结束拆楼</div>

    <div class="build-list">
      <div class="build-item" onclick="chooseFloor('L13')">L13</div>
      <div class="build-item" onclick="chooseFloor('L12')">L12</div>
      <div class="build-item" onclick="chooseFloor('L11')">L11</div>
      <div class="build-item" onclick="chooseFloor('L10')">L10</div>
      <div class="build-item" onclick="chooseFloor('L9')">L9</div>
      <div class="build-item" onclick="chooseFloor('L8')">L8</div>
      <div class="build-item" onclick="chooseFloor('L7')">L7</div>
      <div class="build-item" onclick="chooseFloor('L6')">L6</div>
      <div class="build-item" onclick="chooseFloor('L5')">L5</div>
      <div class="build-item" onclick="chooseFloor('L1-4')">L1-4</div>
    </div>

    <script type="text/javascript">
      // 拆楼建筑名称数组
      const buildNameList = ['L1-4', 'L5', 'L6', 'L7', 'L8', 'L9', 'L10', 'L11', 'L12', 'L13']
      // 拆楼建筑对象,保存id与原始坐标信息
      const buildInfo = {}

      let openState = false, // 建筑开启状态
        openFloor = '', // 当前打开楼层
        moveState = false // 移动状态

      // 效果参数
      const fps = 20, // 动画需要多少帧完成
        risingHeight = 5, // 建筑抬升高度
        distance = 20, // 拆楼距离
        angle = 270 // 拆楼角度，0是x轴即正东方向，逆时针计算

      /**
       * 初始化场景
       */
      const OnLoad = () => {
        const __DigitalTwinPlayer = new DigitalTwinPlayer(HostConfig.Player, {
          domId: 'player',
          apiOptions: {
            onEvent: e => {
              if (e.Data === 'tick end') moveState = false
            },
            //事件监听回调函数
            onReady: async () => {
              // 重置视频流
              await fdapi.reset(2 | 4)
              await fdapi.removeTick()

              // 获取图层树信息
              const { infotree } = await fdapi.infoTree.get()
              // 把图层id存放到一个数组中，方便查询属性
              const idList = []
              infotree.forEach(item => {
                if (buildNameList.includes(item.name)) {
                  idList.push(item.iD)
                }
              })
              // 查询图层属性
              const { data } = await fdapi.tileLayer.get(idList)
              // 存储每个图层对应的属性
              data.forEach((item, index) => {
                buildInfo[buildNameList[index]] = {
                  id: item.id,
                  location: item.location,
                  openLocation: [item.location[0], item.location[1], item.location[2] + (index + 1) * risingHeight]
                }
              })
            }
          }
        })
      }

      // 开始拆楼
      const begin = () => {
        if (openState) {
          console.log('模型已经开启，可点击楼层进行拆楼')
          return
        }
        // 构造setLocationList id,对应结束的位置
        const setLocationList = []
        for (let key in buildInfo) {
          setLocationList.push({
            id: buildInfo[key].id,
            location: buildInfo[key].openLocation
          })
        }
        setLocation(setLocationList)

        // 打开状态设置为开启
        openState = true
      }

      // 点击某一层
      const chooseFloor = name => {
        if (!openState) {
          console.log('\x1b[33m%s\x1b[0m', '请先开启拆楼')
          return
        }

        if (moveState) {
          console.log('\x1b[33m%s\x1b[0m', '模型位移中,请等模型位移结束再操作')
          return
        }

        if (name === buildNameList[buildNameList.length - 1]) {
          console.log('\x1b[33m%s\x1b[0m', '顶层不拆')
          return
        }

        const setLocationList = []

        // 如果已经有打开的楼层，则要把当前楼层回收
        if (openFloor) {
          setLocationList.push({ id: [buildInfo[openFloor].id], location: buildInfo[openFloor].openLocation })

          // 同一层则直接重置当前楼层
          if (openFloor == name) {
            setLocation(setLocationList)
            openFloor = ''
            return
          }
        }

        // 需要位移的楼层:通过起点、角度、距离 计算终点位置
        const startLocation = JSON.parse(JSON.stringify(buildInfo[name].openLocation))
        const endLocation = calculatePoint(startLocation, angle, distance)
        setLocationList.push({ id: [buildInfo[name].id], location: endLocation })
        setLocation(setLocationList)
        openFloor = name // 保存当前楼层信息
      }

      // 模型位移-从当前位置位移到目标位置
      const setLocation = async arr => {
        // 设置移动状态为true
        moveState = true

        const tickUrl = `@path:tick/moveTo.html?data=${JSON.stringify(arr)}&fps=${fps}&.html`
        await fdapi.registerTick(tickUrl)
      }

      // 重置模型
      const reset = async () => {
        if (!openState) {
          console.log('\x1b[33m%s\x1b[0m', '模型不需要重置')
          return
        }

        await fdapi.removeTick()

        fdapi.tileLayer.updateBegin()
        for (let key in buildInfo) {
          fdapi.tileLayer.setLocation(buildInfo[key].id, buildInfo[key].location)
        }
        fdapi.tileLayer.updateEnd()

        openState = false
        openFloor = ''
      }

      // 根据角度和距离计算点
      function calculatePoint(point, angle, distance) {
        var radians = angle * (Math.PI / 180) // 将角度转换为弧度
        var x1 = point[0] + distance * Math.cos(radians)
        var y1 = point[1] + distance * Math.sin(radians)
        return point[2] ? [x1, y1, point[2]] : [x1, y1]
      }

      /**
       * 自适应分辨率
       */
      const onResize = async () => {
        let playerView = document.getElementById('player')
        playerView.style.height = window.innerHeight + 'px'
        playerView.style.width = window.innerWidth + 'px'
      }

      // 页面加载调用
      window.addEventListener('load', OnLoad, true)

      // 页面窗口变换调用
      window.addEventListener('resize', onResize, true)
    </script>
  </body>
</html>
